﻿#include "audio_player.h"
#include <iostream>
#include <cmath>

//静态变量初始化
std::set<std::string> AudioPlayer::nameSet;
long long int AudioPlayer::defaultNameCount = 0;

// 静态方法, 检查id是否已经存在
bool AudioPlayer::includeID(const std::string id) {
    return nameSet.count(id);
}

AudioPlayer::AudioPlayer() : volume(100.f),isLooping_(true), 
    isPlaying_(false), isFading(false), initialized(false){
    //用于输出有汉字的wstring
    std::wcout.imbue(std::locale("chs"));

}

AudioPlayer::~AudioPlayer() {
    if (initialized) {
        std::wstring command = L"close " + nameW;
        int returnCode = mciSendStringW(command.c_str(), NULL, 0, NULL);
        if (returnCode != 0) {
            std::cerr << ("Warning: ~AudioPlayer: fail to close " + name + ". mciSendString return code: ") << returnCode << std::endl;
            std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        }
        nameSet.erase(name);
    }
    else {
        std::cerr << ("Warning: ~AudioPlayer: " + name + " is not initialized.") << std::endl;
    }
    
}

// 初始化
bool AudioPlayer::init(const std::string& filePath_, const std::string& name_, bool loop) {
    if (initialized) {
        std::cerr << ("Warning: " + name + " has already been initialized.") << std::endl;
        return false;
    }
    filePath = filePath_;
    name = name_;

    if (name == "") {
        //使用默认名称
        name = "defaultAudioName" + std::to_string(defaultNameCount);
        defaultNameCount++;

        while (nameSet.count(name)) {
            name = "defaultAudioName" + std::to_string(defaultNameCount);
            defaultNameCount++;
        }
    }
    else {
        //使用传入的名字
        //删除name中的空白字符
        name.erase(std::remove_if(name.begin(), name.end(), [](unsigned char c) {
            return std::isspace(c);
        }), name.end());
        if (name != name_) {
            std::cerr << ("Warning: AudioPlayer: The name \"" + name_ + "\" is invalid. The name has been transformed into \"" + name + "\".") << std::endl;
        }
    }

    
    if (nameSet.count(name)) {
        std::cerr << ("Error: AudioPlayer: The name \"" + name_ + "\" already exists. Initialization failed.") << std::endl;
        return false;
    }
    try {
        nameW = utils::utf8ToWide(name);
    }
    catch (const std::exception& e) {
        // 记录异常信息
        std::cerr << "Error: AudioPlayer: utf8ToWide exception: " << e.what() << std::endl;
        return false;
    }


    // 打开音频文件
    std::wstring openCommand = L"open \"" + utils::utf8ToWide(filePath) + L"\" type mpegvideo alias " + nameW;
    int returnCode = mciSendStringW(openCommand.c_str(), NULL, 0, NULL);
    if (returnCode != 0) {
        std::cerr << ("Error: AudioPlayer: fail to open audio file \"" + filePath + "\". mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return false;
    }
    nameSet.insert(name);
    isLooping_ = loop;
    initialized = true;
    return true;
}

void AudioPlayer:: checkPlayCompleted() {
    if (!isLooping_ && getPlayingOffset() >= getDuration()) {
        isPlaying_ = false;
        std::wstring command = L"seek " + nameW + L" to start";
        int returnCode = mciSendStringW(command.c_str(), NULL, 0, NULL);
        if (returnCode != 0) {
            std::cerr << ("Warning: checkPlayCompleted: " + name + " fail to seek to start. mciSendString return code: ") << returnCode << std::endl;
            std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
            return;
        }
    }
}


bool AudioPlayer::isInitialized()const {
    return initialized;
}

bool AudioPlayer::play() {
    
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to play.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    if (isPlaying_) {
        std::cerr << ("Warning: " + name + " is playing. Do not need to play again.") << std::endl;
        return true;
    }

    // 设置音量
    setVolume(volume);

    // 播放音频
    std::wstring playCommand = L"play " + nameW;
    if (isLooping_) {
        playCommand += L" repeat";
    }
    int returnCode = mciSendStringW(playCommand.c_str(), NULL, 0, NULL);
    if (returnCode != 0) {
        std::cerr << ("Error: " + name + " fail to play. mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return false;
    }

    isPlaying_ = true;
    return true;
}

bool AudioPlayer::pause() {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to pause.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    if (!isPlaying_) {
        std::cerr << ("Warning: " + name + " is not playing, can not pause.") << std::endl;
        return true;
    }
    std::wstring command = L"pause " + nameW;
    int returnCode = mciSendStringW(command.c_str(), NULL, 0, NULL);
    if (returnCode != 0) {
        std::cerr << ("Warning: " + name + " fail to pause. mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return false;
    }
    isPlaying_ = false;
    return true;
}

bool AudioPlayer::restart() {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to restart.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    if (isPlaying_) {
        pause();
    }
    std::wstring command = L"seek " + nameW + L" to start";
    int returnCode = mciSendStringW(command.c_str(), NULL, 0, NULL);
    if (returnCode != 0) {
        std::cerr << ("Warning: " + name + " fail to restart. mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return false;
    }
    return play();
}

bool AudioPlayer::setLoop(bool loop) {
    if (!initialized) {
        std::cerr << ("Warning: " + name + " is not initialized, fail to set loop.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    isLooping_ = loop;

    return true;
}

bool AudioPlayer::setVolume(float volume_) {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to set volume.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    // 限制音量范围在0-100
    this->volume = utils::MAX(0.f, utils::MIN(100.f, volume_));
    if (volume_ < 0.f || volume_ > 100.f) {
        std::cerr << ("Warning: the argument of AudioPlayer::setVolume is not in [0,100] and has been transformed to ")<< volume << std::endl;
    }

    
    
    std::wstring command = L"setaudio " + nameW + L" volume to " + std::to_wstring(static_cast<int>(this->volume * 10));
    int returnCode = mciSendStringW(command.c_str(), NULL, 0, NULL);
    if (returnCode != 0) {
        std::cerr << ("Warning: " + name + " fail to set volume. mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return false;
    }
    return true;
    
   
}



float AudioPlayer::getVolume() const {
    return volume;
}

bool AudioPlayer::fadeIn(float durationSeconds) {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to fade in.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    if (isPlaying()) {
        std::cerr << ("Warning: " + name + " is playing before fade in.") << std::endl;
    }
    else {
        play();
    }
    
    return fade(0.f, volume, durationSeconds);
}

bool AudioPlayer::fadeOut(float durationSeconds) {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to fade out.") << std::endl;
        return false;
    }
    checkPlayCompleted();
    if (!isPlaying_) {
        std::cerr << ("Warning: " + name + " is not playing before fade out.") << std::endl;
        play();
    }
    return fade(volume, 0.f, durationSeconds);
}

bool AudioPlayer::isPlaying() {
    checkPlayCompleted();
    return isPlaying_;
}

bool AudioPlayer::isLooping() const {
    return isLooping_;
}

float AudioPlayer::getDuration() const {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to get duration.") << std::endl;
        return 0.0f;
    }
    wchar_t durationBuffer[128] = { 0 };
    std::wstring command = L"status " + nameW + L" length";
    //mciSendString将durationBuffer设置为音频时长，毫秒级
    int returnCode = mciSendStringW(command.c_str(), durationBuffer, 128, NULL);
    if (returnCode != 0) {
        std::cerr << ("Warning: " + name + " fail to get duration. mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return 0.0f;
    }
    return static_cast<float>(_wtoi(durationBuffer)) / 1000.0f;//转换为秒
}

float AudioPlayer::getPlayingOffset() const {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to get offset.") << std::endl;
        return 0.0f;
    }
    wchar_t positionBuffer[128] = { 0 };
    std::wstring command = L"status " + nameW + L" position";
    //mciSendString获取当前播放到的时间点
    int returnCode = mciSendStringW(command.c_str(), positionBuffer, 128, NULL);
    if (returnCode != 0) {
        std::cerr << ("Warning: " + name + " fail to get offset. mciSendString return code: ") << returnCode << std::endl;
        std::wcout << utils::GetMciErrorText(returnCode) << std::endl;
        return 0.0f;
    }
    return static_cast<float>(_wtoi(positionBuffer)) / 1000.0f;
}

bool AudioPlayer::fade(float startVolume, float targetVolume, float durationSeconds) {
    if (!initialized) {
        std::cerr << ("Error: " + name + " is not initialized, fail to start fade.") << std::endl;
        return false;
    }
    if (isFading) {
        std::cerr << ("Warning: " + name + " is fading, fail to restart fading. ") << std::endl;
        return false;
    }
    if (durationSeconds <= 0) {
        std::cerr << ("Warning: " + name + "'s fade durationSeconds is less than 0. ") << std::endl;
        setVolume(targetVolume);
        return false;
    }

    isFading = true;
   
    try {
        const float updateInterval = 0.2f; // 200ms
        const int steps = static_cast<int>(durationSeconds / updateInterval);
        const float volumeStep = (targetVolume - startVolume) / steps;

        float currentVolume = startVolume;
        setVolume(startVolume);
        //循环设置音量
        for (int i = 0; i < steps; ++i) {
            currentVolume += volumeStep;   
            setVolume(currentVolume);

            // 等待更新间隔
            std::this_thread::sleep_for(std::chrono::milliseconds(int(updateInterval*1000)));
            
        }

        // 确保音量精确达到目标值
        
        setVolume(targetVolume);
        if (targetVolume <= 0.1f) {
            pause();
        }
        
    }
    catch (const std::exception& e) {
        // 记录异常信息
        std::cerr << "Error: Fade thread exception: " << e.what() << std::endl;

        // 恢复状态
        
        setVolume(targetVolume); // 尝试设置目标音量
        // 无论是否发生异常，都清理状态
        isFading = false;
        return false;
        
    }
    catch (...) {
        // 处理未知异常
        std::cerr << "Error: Fade thread unknown exception" << std::endl;
        // 无论是否发生异常，都清理状态
        isFading = false;
        return false;
    }

    // 无论是否发生异常，都清理状态
    isFading = false;
    return true;

}


